#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define TNUM 4

typedef void (*func_t)(const string &, pthread_mutex_t *, pthread_cond_t *);
volatile bool quit = false;
int cnt = 10;


class ThreadData
{
public:
    ThreadData(const string &name, func_t func, pthread_mutex_t *mtx, pthread_cond_t *cond)
        : _name(name), _func(func), _pmtx(mtx), _pcond(cond)
    {
    }

    string _name;
    func_t _func;
    pthread_mutex_t *_pmtx;
    pthread_cond_t *_pcond;
};

void func1(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (true)
    {
        pthread_mutex_lock(pmtx);
        // cout << quit << endl;
        if (cnt <= 0) // 所以不能对quit做判断，而是cnt
        {
            pthread_mutex_unlock(pmtx);
            break;
        }
        else
        {
            pthread_cond_wait(pcond, pmtx);
            cout << name << endl;
        }
        pthread_mutex_unlock(pmtx);

        // sleep(1);
    }
}

void *Entry(void *args) // 入口函数
{
    ThreadData *td = (ThreadData *)args;
    td->_func(td->_name, td->_pmtx, td->_pcond);
    delete td;
    return nullptr;
}

int main()
{
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    pthread_t tid[TNUM];
    for (int i = 0; i < TNUM; i++)
    {
        string name = "New Thread ";
        name += to_string(i + 1);
        ThreadData *td = new ThreadData(name, func1, &mtx, &cond);
        pthread_create(tid + i, nullptr, Entry, (void *)td);
    }
    // 等待新线程被调度
    // 主线程如果不等，继续向下执行，新线程还没有被调度，也就没有条件wait，
    // 这个时候向新线程发信号是没有用的，直接忽略
    sleep(1);

    // 主线程调用
    while (cnt > 0)
    {
        cout << "running..." << cnt-- << endl;
        pthread_cond_broadcast(&cond);
        sleep(1);
        // 在主线程的时间片中，如果不sleep，新线程就可能还没有被调度，没有wait
    }

    quit = true;
    // 上面的sleep就会导致，quit设置的不及时，quit判断不及时，新线程已经wait上了
    pthread_cond_broadcast(&cond);

    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tid[i], nullptr);
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}